package com.xbongbong.pro.statistics.strategy.chart.type.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.xbongbong.paas.bi.pojo.vo.DataSetResultVO;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.XbbConstant;
import com.xbongbong.paas.enums.AggTypeEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.pro.bi.commons.pojo.AggFieldPojo;
import com.xbongbong.pro.bi.commons.pojo.vo.GroupSqlVO;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.statistic.pojo.ChartFieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.ChartResultPojo;
import com.xbongbong.pro.statistic.result.pojo.FieldAttrPojo;
import com.xbongbong.pro.statistic.result.pojo.vo.ChartAnalysisVO;
import com.xbongbong.pro.statistics.enums.StatisticsSumEnum;
import com.xbongbong.pro.statistics.help.DescribeTableHelper;
import com.xbongbong.pro.statistics.help.DisplayHelper;
import com.xbongbong.pro.statistics.help.InitSqlHelper;
import com.xbongbong.pro.statistics.help.StatisticsTableVOHelper;
import com.xbongbong.pro.statistics.helper.AggHelper;
import com.xbongbong.pro.statistics.helper.ChartDataSetHelper;
import com.xbongbong.pro.statistics.pojo.dto.ChartAnalysisDTO;
import com.xbongbong.pro.statistics.pojo.dto.GenerateSqlDTO;
import com.xbongbong.pro.statistics.pojo.vo.GenerateSqlVO;
import com.xbongbong.pro.statistics.strategy.chart.type.ChartTypeStrategyService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

import static com.xbongbong.pro.statistics.enums.StatisticsSumEnum.getEnumBySum;

/**
 * 统计表
 * @ClassName DataStatisticsTableStrategyServiceImpl
 * @Author 梁鲁江
 * 创建时间 2022/9/21 14:21
 * 修改时间  2022/9/21 14:21
 **/
@Service
public class DataStatisticsTableStrategyServiceImpl implements ChartTypeStrategyService {
    @Resource
    private ChartDataSetHelper chartDataSetHelper;
    @Resource
    private DisplayHelper displayHelper;
    @Resource
    private DescribeTableHelper describeTableHelper;
    @Resource
    private StatisticsTableVOHelper statisticsTableVOHelper;
    @Resource
    private InitSqlHelper initSqlHelper;
    @Resource
    private AggHelper aggHelper;
    @Override
    public ChartAnalysisVO chartAnalysis(ChartAnalysisDTO chartAnalysisDTO) throws XbbException {
        Map<String, Map<String, String>> attrLinkMap = aggHelper.getLinkMap(chartAnalysisDTO.getChartEntity(),  chartAnalysisDTO.getResultArray());
        return statisticsTableVOHelper.statisticsChartAnalysis(chartAnalysisDTO,attrLinkMap);
    }

    @Override
    public GenerateSqlVO generateSql(GenerateSqlDTO generateSqlDTO) throws XbbException {
        GenerateSqlVO generateSqlVO = new GenerateSqlVO();
        ChartEntity chartEntity = generateSqlDTO.getChartEntity();
        //行列分组的时候
        if (chartEntity.getRowGroupAttr()==null || chartEntity.getColGroupAttr()==null ||((chartEntity.getRowGroupAttr()!=null && chartEntity.getRowGroupAttr().size() <= 0) && (chartEntity.getColGroupAttr()!=null && chartEntity.getColGroupAttr().size() <= 0))) {
            return generateSqlVO;
        }
        //统计表没有选择汇总字段直接返回
        if(chartEntity.getSummaryAttr()==null || chartEntity.getSummaryAttr().size()<=0){
            return generateSqlVO;
        }
        ChartResultPojo chartResultPojo = generateSqlDTO.getChartResultPojo();
        
        //String parseSql = chartDataSetHelper.getDataSetParseSql(generateSqlDTO, chartEntity);
        DataSetResultVO dataSetResultVO = chartDataSetHelper.getDataSetParseSql(generateSqlDTO, chartEntity);
        String parseSql = dataSetResultVO.getParseSql();

        Map<String, String> sortFieldMap = displayHelper.getAggSortMap(chartEntity, chartResultPojo.getSortStatisticsMap(),chartResultPojo.getSortFieldOrder());
        //查询条件和筛选条件放在一起
        String filter = describeTableHelper.filterField(chartEntity);
        int limit = 1000;
        limit = describeTableHelper.statisticsLimit(chartEntity, chartResultPojo, limit);
        //分组字段放在colums
        List<String> groupColumnsList = new ArrayList<>();
        List<String> rowGroupColumnsList = new ArrayList<>();
        List<String> colGroupColumnsList = new ArrayList<>();
        //分组字段放在group by 
        List<String> groupFieldsList = new ArrayList<>();
        List<String> rowGroupFieldsList = new ArrayList<>();
        List<String> colGroupFieldsList = new ArrayList<>();
        Map<String, AggFieldPojo>  aggFieldMap = new LinkedHashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<String> aggFieldsList = new ArrayList<>();
        JSONArray rowGroupAttr = chartEntity.getRowGroupAttr();
        JSONArray colGroupAttr = chartEntity.getColGroupAttr();
        //保存下拉类型的字段
        Map<String,FieldAttrPojo> comboFieldMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        HashMap<String, Set<String>> selectItemsMap = Maps.newHashMap();
        if(rowGroupAttr !=null && rowGroupAttr.size() > 0){
            List<FieldAttrPojo> rowGroupAttrList = JSONArray.parseArray(rowGroupAttr.toJSONString(), FieldAttrPojo.class);
            if (CollectionsUtil.isNotEmpty(rowGroupAttrList)) {
                for (FieldAttrPojo fieldAttrPojo : rowGroupAttrList) {
                    aggHelper.setGroupField(rowGroupColumnsList, rowGroupFieldsList, fieldAttrPojo, comboFieldMap, chartEntity, sortFieldMap);
                }
            }
            groupColumnsList.addAll(rowGroupColumnsList);
            groupFieldsList.addAll(rowGroupFieldsList);
        }
        if(colGroupAttr !=null && colGroupAttr.size() > 0){
            List<FieldAttrPojo> colGroupAttrList = JSONArray.parseArray(colGroupAttr.toJSONString(), FieldAttrPojo.class);
//            setGroupFields(selectItemsMap,formIdTableMap, sortMap, rowGroupColumnsList, rowGroupFieldsList, isSingle, colGroupAttrList, chartEntity);
            if (CollectionsUtil.isNotEmpty(colGroupAttrList)) {
                for (FieldAttrPojo fieldAttrPojo : colGroupAttrList) {
                    aggHelper.setGroupField(colGroupColumnsList, colGroupFieldsList, fieldAttrPojo, comboFieldMap, chartEntity, sortFieldMap);
                }
            }
            groupColumnsList.addAll(colGroupColumnsList);
            groupFieldsList.addAll(colGroupFieldsList);
        }

        List<ChartFieldAttrPojo> list = JSONArray.parseArray(chartEntity.getSummaryAttr().toJSONString(), ChartFieldAttrPojo.class);
        List<String> sumTotalFieldsList = new ArrayList<>();
        List<String> subQuerySqlOfCountList = new ArrayList<>();
        List<String> summaryColumnAlisa = new ArrayList<>();
        for (ChartFieldAttrPojo fieldAttrPojo : list) {
            AggTypeEnum aggTypeEnum = AggTypeEnum.getByAlias(fieldAttrPojo.getAggType());
            if(Objects.equals(fieldAttrPojo.getAttr(),PaasConstant.COUNT)){
                aggTypeEnum =  AggTypeEnum.COUNT;
            }
            String attr = fieldAttrPojo.getAttr();
            if (Objects.equals(FieldTypeEnum.COMPUTED_FIELD.getType(), fieldAttrPojo.getFieldType())) {
                aggHelper.addComputedField(chartEntity,PaasConstant.LEFT,aggFieldMap, aggFieldsList,fieldAttrPojo,aggTypeEnum,sumTotalFieldsList,subQuerySqlOfCountList,summaryColumnAlisa);
            } else {
                aggHelper.addValuesField(PaasConstant.LEFT, aggFieldMap, aggFieldsList, fieldAttrPojo, aggTypeEnum, attr,sortFieldMap, sumTotalFieldsList,summaryColumnAlisa);
            }
        }

        GroupSqlVO groupSqlVO = GroupSqlVO.initGroupSqlVO(rowGroupFieldsList, colGroupFieldsList, rowGroupColumnsList, colGroupColumnsList, sumTotalFieldsList, aggFieldMap, comboFieldMap,groupFieldsList);
        groupSqlVO.setSubQuerySqlOfCountList(subQuerySqlOfCountList);
        groupSqlVO.setSummaryColumnAlisa(summaryColumnAlisa);
        initSqlHelper.buildSubColumnOfCount(groupSqlVO,groupColumnsList,Boolean.FALSE);

        groupColumnsList.addAll(aggFieldsList);
        //","分割
        String colums = String.join(XbbConstant.SQL_COMMA, groupColumnsList);
        String groupFields = String.join(XbbConstant.SQL_COMMA, groupFieldsList);
        String sortField = displayHelper.getDsAggSortField(sortFieldMap,groupSqlVO);
        StringBuffer sql = chartDataSetHelper.tableSqlAppend(parseSql, colums, sortField, filter, limit, 0, groupFields, false, groupSqlVO);
        int pageSize =  XbbConstant.STATISTICS_PAGE_SIZE;
        PageHelper pageHelper = new PageHelper(chartResultPojo.getPage(), pageSize);
        generateSqlVO.setPageHelper(pageHelper);
        generateSqlVO.setStringBufferSql(sql);
        generateSqlVO.setAggFieldMap(aggFieldMap);
        //统计表总计、小计的sql处理
        dsTotalOrSubtotalSqlHandle(generateSqlVO, chartEntity, parseSql, filter, groupSqlVO);
        return generateSqlVO;
    }

    /**
     * 获取统计表 总计、小计、总计&小计的sql（跟ck不通用）
     *
     * @param generateSqlVO
     * @param chartEntity
     * @param fromSql
     * @param whereSql
     * @param groupSqlVO
     * @author zyy
     * @date 2022/10/19
     * @version v1.0
     */
    private void dsTotalOrSubtotalSqlHandle(GenerateSqlVO generateSqlVO, ChartEntity chartEntity, String fromSql, String whereSql, GroupSqlVO groupSqlVO) throws XbbException {
        //如果是子查询SQL，那么原有的resultSql语句是完整的SQL，内层的存到groupSqlVO里了
//        if(StringUtils.isNotBlank(groupSqlVO.getSubCompleteSqlOfCount())){
//            fromSql = groupSqlVO.getSubCompleteSqlOfCount();
//        }
        StatisticsSumEnum statisticsSumEnum = getEnumBySum(chartEntity.getSum());
        switch (statisticsSumEnum) {
            case SUB_TOTAL:
                //小计
                subtotalSqlHandle(generateSqlVO,chartEntity,fromSql,whereSql,groupSqlVO);
                break;
            case ALL:
                //总计 & 小计
                subtotalSqlHandle(generateSqlVO,chartEntity,fromSql,whereSql,groupSqlVO);
                totalSqlHandle(generateSqlVO,fromSql,whereSql,groupSqlVO);
                break;
            default:
                //默认为总计
                totalSqlHandle(generateSqlVO,fromSql,whereSql,groupSqlVO);
                break;
        }
    }

    private void subtotalSqlHandle(GenerateSqlVO generateSqlVO, ChartEntity chartEntity, String fromSql, String whereSql, GroupSqlVO groupSqlVO) throws XbbException {
        //没有行分组则不计算小计
        if(CollectionUtils.isEmpty(groupSqlVO.getRowGroupColumnsList())){
            return;
        }
        //获取行分组,只获取第一层
        List<String> subTotalGroupColumnList = new ArrayList<>();
        List<String> subTotalGroupFieldList = new ArrayList<>();

        JSONObject originalRowField = chartEntity.getOriginalRowField();
        if(Objects.nonNull(originalRowField)){
            FieldAttrPojo fieldAttrPojo = originalRowField.toJavaObject(FieldAttrPojo.class);
            aggHelper.setGroupField(subTotalGroupColumnList, subTotalGroupFieldList, fieldAttrPojo, Maps.newHashMap(), chartEntity, Maps.newHashMap());
        }else{
            subTotalGroupColumnList.add(groupSqlVO.getRowGroupColumnsList().get(0));
            subTotalGroupFieldList.add(groupSqlVO.getRowGroupFieldsList().get(0));
        }

        subTotalGroupColumnList.add(groupSqlVO.getRowGroupColumnsList().get(0));
        subTotalGroupFieldList.add(groupSqlVO.getRowGroupFieldsList().get(0));
        //获取列分组,获取到最后一层
        if(CollectionUtils.isNotEmpty(groupSqlVO.getColGroupColumnsList())){
            subTotalGroupColumnList.addAll(groupSqlVO.getColGroupColumnsList());
            subTotalGroupFieldList.addAll(groupSqlVO.getColGroupFieldsList());
        }
        String groupColumn = String.join(",",subTotalGroupColumnList);
        String groupField = String.join(",",subTotalGroupFieldList);

        String columnStr = mergeColumn(groupColumn,groupSqlVO.getSumTotalFieldsList());
        StringBuffer subTotalSqlBuilder = chartDataSetHelper.tableSqlAppend(fromSql, columnStr, "", whereSql, null, null, groupField, false, null);
        String subTotalSql = subTotalSqlBuilder.toString();
        subTotalSql = statisticsTableVOHelper.dealSubQuerySqlByCount(subTotalSql,groupSqlVO,groupColumn,Boolean.FALSE);
        generateSqlVO.setSubTotalSql(subTotalSql);
    }

    private void totalSqlHandle(GenerateSqlVO generateSqlVO, String fromSql, String whereSql, GroupSqlVO groupSqlVO) throws XbbException {
        //统计表第一象限
        if(CollectionsUtil.isNotEmpty(groupSqlVO.getColGroupColumnsList())){
            Map<String,String> rightGroupSqlMap = statisticsTableVOHelper.getGroupSqlOfTotal(groupSqlVO,false);
            String rightTotalColumn = mergeColumn(rightGroupSqlMap.get("groupColumn"),groupSqlVO.getSumTotalFieldsList());
            StringBuffer rightTotalSqlBuilder = chartDataSetHelper.tableSqlAppend(fromSql, rightTotalColumn, "", whereSql, null, null,rightGroupSqlMap.get("groupField"), false, null);
            String rightTotalSql = rightTotalSqlBuilder.toString();
            rightTotalSql = statisticsTableVOHelper.dealSubQuerySqlByCount(rightTotalSql,groupSqlVO,rightGroupSqlMap.get("groupColumn"),Boolean.FALSE);
            generateSqlVO.setSumRightTotalSql(rightTotalSql);
        }

        //统计表第三象限
        Map<String,String> underSqlMap = statisticsTableVOHelper.getGroupSqlOfTotal(groupSqlVO,true);
        String underSqlColumn = mergeColumn(underSqlMap.get("groupColumn"),groupSqlVO.getSumTotalFieldsList());
        StringBuffer underTotalSqlBuilder = chartDataSetHelper.tableSqlAppend(fromSql, underSqlColumn, "", whereSql, null, null,underSqlMap.get("groupField"), false, null);
        String underTotalSql = underTotalSqlBuilder.toString();
        underTotalSql = statisticsTableVOHelper.dealSubQuerySqlByCount(underTotalSql,groupSqlVO,underSqlMap.get("groupColumn"),Boolean.FALSE);
        generateSqlVO.setSumTotalSql(underTotalSql);

        //统计表第四象限
        if(statisticsTableVOHelper.containsComputedField(groupSqlVO.getAggFieldMap(),groupSqlVO.getColGroupColumnsList())){
            //只拼接 select部分 跟 from部分 ，不进行分组（最大的数据范围）
            String totalOfTotalSqlColumn = mergeColumn("",groupSqlVO.getSumTotalFieldsList());
            StringBuffer totalOfTotalSqlBuilder = chartDataSetHelper.tableSqlAppend(fromSql, totalOfTotalSqlColumn, "", whereSql, null, null,"", false, null);
            String totalOfTotalSql = totalOfTotalSqlBuilder.toString();
            totalOfTotalSql = statisticsTableVOHelper.dealSubQuerySqlByCount(totalOfTotalSql,groupSqlVO,"",Boolean.FALSE);
            generateSqlVO.setTotalOfTotalSql(totalOfTotalSql);
        }
    }

    /**
     * 合并汇总字段跟分组字段
     *
     * @param groupColumn
     * @param sumTotalFieldsList
     * @return java.lang.String
     * @author zyy
     * @date 2022/10/19
     * @version v1.0
     */
    private String mergeColumn(String groupColumn, List<String> sumTotalFieldsList) {
        String columnStr = String.join(XbbConstant.SQL_COMMA, sumTotalFieldsList);
        if(StringUtils.isNotBlank(groupColumn)){
            columnStr = columnStr + XbbConstant.SQL_COMMA + groupColumn;
        }
        return columnStr;
    }


}


